일 잘하는 엔지니어의 생각 기법 중, 027 측정 침입에 관한 나의 에피소드.
고대에 아마도 시리얼 EEPROM에 MAC 어드레스를 write 하는 코드였던 것 같다.
부팅 시에 MAC이 비었으면 콘솔에서 수동으로 입력하는 요건이다.
이 기능이 디버깅 모드에서는 잘 도는데 릴리즈 모드에서는 돌지 않는다.
원인을 찾다찾다 보니까, (기억이 흐릿하긴 하지만)
디버깅 메시지를 출력하는 타이밍 지연이 발생하면서 I2S (어쩌면 SPI) 직접 타이밍 제어가 꼬였던 것.
측정 (디버깅 메시지)을 위한 도구로 인해 외부 효과가 발생한 사연이다.
이런 현상은 사실 더 대놓고 보란듯이 일어나며, 이렇게 깊이 숨지 않고 예측 가능한 범위에 있는 것이 대부분이다.
성능 프로파일링에 있어서 흔한 기법은 주요 함수를 후킹하는 것이다.
후킹의 구조는 이렇다.
실제 동작해야 할 함수 A가 있을 때,
프로파일링 기능이 탑재된 함수 B를 만들고,
A를 호출하면 B가 먼저 호출되도록 손을 써 놓는다.
리눅스라면 LD_PRELOAD, LD_LIBRARY_PATH에 의한 해킹 기법이 바로 이것이며, 고대에 모든 시스템콜을 후킹하여 2중 퍼미션, 감사 로깅을 남기는 기능들도 비슷한 방식으로 동작한다.
여기에서 성능 손실이 일어난다.
이제 A를 호출하면 B를 실행하고, B는 성능 정보를 외부에 기록하고, 진짜 A를 호출하고, A가 끝나면 다시 성능 정보를 외부에 기록하고 본체에 리턴한다.
함수 호출이 더 생겼으니 그 사이에 함수 리턴등에 의한 CSW, 스택 작업, 모드 전환, 외부 로깅등의 부하가 생긴다.
아예 회로적인 기법은 상대적으로 이런 부하에서 자유롭다.
스위칭 허브가 아닌 더미 허브에서 모든 패킷을 감청하거나, 전용 장비를 이용하거나, JTAG/ICE 등의 기법등이 그렇다.
회로의 신호를 관측만 하는 것이기에 추가적인 부하가 없는 경우가 대부분이다.
다른 이야기지만, 디버그/릴리즈 빌드에서 예상치 않은 버그가 발생하는 경우도 많다.
릴리즈 빌드에서 디버그 빌드의 코드가 홀랑 날아가거나, 컴파일러 최적화가 문제를 일으키거나(volatile 문제 등)하는 일들이 있다. 또는, 구멍이 있는 락(동기화)코드가 디버그 모드에서는 우연히 락 대기의 타이밍이 맞아서 잘 돌았는데, 릴리즈 모드에서 락의 버그가 비로소 출현하는 경우도 있다.
아예 잘 설계된 성능 프로파일링 프레임워크에 의존하는 방법도 좋다. 손을 놓은지 시간이 흘러서 정확히 쓰긴 어렵지만, cuda의 경우 하드웨어 지원에 의한 훌륭한 프로파일링을 제공한다.